﻿using System;
using System.Linq;
using System.Linq.Expressions;

namespace Affinity.Synthesis.ExpressionCells.Basis
{
    /// <summary>
    /// Expression cell class representing a ParameterExpression.
    /// </summary>
    internal class ParameterExpressionCell : ExpressionCellBase
    {
        /// <summary>
        /// Constructor accepting the ordinal (position) and ParameterExpression for a parameter.
        /// </summary>
        /// <param name="ordinal"></param>
        /// <param name="sourceExpression"></param>
        public ParameterExpressionCell(int ordinal, ParameterExpression sourceExpression)
            : base(sourceExpression)
        {
            _Ordinal = ordinal;
        }

        /// <summary>
        /// Copy constructor.
        /// </summary>
        /// <param name="existing"></param>
        protected ParameterExpressionCell(ParameterExpressionCell existing)
            : base(existing)
        {
            _Ordinal = existing._Ordinal;
        }

        /// <summary>
        /// Gets or sets the ExpressionCellValue representing the single input to this ParameterExpressionCell.
        /// </summary>
        public ExpressionCellValue Input
        {
            get { return Inputs.FirstOrDefault(); }
            set { Inputs = new ExpressionCellValue[] { value }; }
        }

        /// <summary>
        /// Gets the ordinal (position) of the parameter.
        /// </summary>
        public int Ordinal
        {
            get { return _Ordinal; }
        }

        /// <summary>
        /// Creates and returns a copy of this expression cell.
        /// </summary>
        /// <returns></returns>
        public override IExpressionCell Copy()
        {
            return new ParameterExpressionCell(this);
        }

        /// <summary>
        /// Returns a description of this expression cell.
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return string.Format("{0}: Slot {1}", base.ToString(), _Ordinal);
        }

        /// <summary>
        /// "Calculates" the output of this expression cell by passing along the input value if the input is present and has a value.
        /// </summary>
        /// <param name="inputs"></param>
        /// <param name="hasValue"></param>
        /// <param name="value"></param>
        protected override void CalculateOutput(object[] inputs, out bool hasValue, out object value)
        {
            hasValue = Input != null && Input.HasValue;
            value = hasValue ? Input.Value : null;
        }

        private int _Ordinal = -1;
    }
}
